# 1.导包
import tensorflow as tf
import matplotlib.pyplot as plt
from tensorflow.keras.datasets import cifar10
import numpy as np

# 使用cifar10.load_data()函数加载CIFAR-10数据集，返回训练集和测试集的数据和标签。
# 打印训练集的图像数据形状（X_train.shape）和标签数据形状（y_train.shape）。
# 打印测试集的图像数据形状（X_test.shape）和标签数据形状（y_test.shape）。
(X_train,y_train),(X_test,y_test)=cifar10.load_data()
print(X_train.shape,y_train.shape)
print(X_test.shape,y_test.shape)


#CIFAR-10 是由Hinton 的学生Alex Krizhevsky 和Ilya Sutskever整理的一个用于识别普适物体的小型数据集。
# 一共包含10 个类别的RGB 彩色图片：
# 飞机（ airplane ）、汽车（ automobile ）、鸟类（ bird ）、猫（ cat ）、鹿（ deer ）、
# 狗（ dog ）、蛙类（ frog ）、马（ horse ）、船（ ship ）和卡车（ truck ）。
# CIFAR-10数据集中每个图片的尺寸为32 × 32 ，每个类别有6000个图像，数据集中一共有50000 张训练图片和10000 张测试图片。
#2.单个数据展示


# 使用plt.figure(figsize=(3,3))设置图像的大小为3x3英寸。
# 使用plt.subplot(2,2,1)创建一个2x2的子图网格，并在第一个位置显示图像X_train[99]。
# 使用plt.subplot(2,2,2)在第二个位置显示图像X_train[100]。
# 使用plt.subplot(2,2,3)在第三个位置显示图像X_train[101]。
# 使用plt.subplot(2,2,4)在第四个位置显示图像X_train[102]。
# 使用plt.xticks([])和plt.yticks([])隐藏x轴和y轴的刻度。
# 使用plt.show()显示图像。
# 使用print(y_train[10])打印第10个标签。
plt.figure(figsize=(3,3))
plt.subplot(2,2,1)
plt.imshow(X_train[99])
plt.subplot(2,2,2)
plt.imshow(X_train[100])
plt.subplot(2,2,3)
plt.imshow(X_train[101])
plt.subplot(2,2,4)
plt.imshow(X_train[102])
plt.xticks([])
plt.yticks([])
plt.show()
print(y_train[10])

print(type(int(y_train[0])))
print(y_train[0])


#3.多个数据展示
# 飞机（ airplane ）、汽车（ automobile ）、鸟类（ bird ）、猫（ cat ）、鹿（ deer ）、
# 狗（ dog ）、蛙类（ frog ）、马（ horse ）、船（ ship ）和卡车（ truck ）。

classes1=['airplane','automobile','bird','cat','deer','dog','frog','horse','ship','truck']
classes2=['飞机','汽车','鸟类','猫','鹿','狗','蛙类','马','船','卡车']
def plot_image(images,labels,pred,index,nums=10):
    plt.rcParams['font.sans-serif']=['SimHei']
    plt.rcParams["axes.unicode_minus"]=False
    fig=plt.gcf()
    fig.set_size_inches(6,3)
    for i in range(nums):
        ax=plt.subplot(2,5,i+1)
        ax.imshow(images[index])
        title='labels:'+classes2[int(labels[index])]
        ax.set_title(title,fontsize=8)
        ax.set_xticks([])
        ax.set_yticks([])
        index+=1
    plt.show()
plot_image(X_train,y_train,'',0)


#4.数据处理
# 特征值归一化
# 将训练集和测试集的图像数据进行归一化处理。
# 通过将每个像素值除以255，可以将图像数据的范围缩放到0到1之间。
# 这样做可以使得模型更容易学习特征，并且提高训练效果。
X_train=X_train/255.
X_test=X_test/255.


#标签值one-hot编码
# 独热编码是一种常用的表示类别变量的方法，
# 它将每个类别映射为一个二进制向量，
# 其中只有一个元素为1，其余元素为0
from tensorflow.keras.utils import to_categorical
y_train=to_categorical(y_train)
y_test=to_categorical(y_test)
print(y_train[0])

#搭建模型
from tensorflow.keras.layers import Dense,Flatten,Input,Dropout
from tensorflow.keras.models import Sequential
mobileNet = MobileNet(include_top=False,weights='imagenet')
model=Sequential()
# model.add(Dense(1000,input_shape=(32,32,3),activation='relu'))
# 定义了输入层的维度为32x32x3，表示图像的宽度、高度和通道数。
# 这里假设输入的图像是彩色图像，具有RGB三个通道。
model.add(Input(shape=(32,32,3)))
# 将输入的多维张量展平为一维向量，以便后续的全连接层处理。
model.add(Flatten())
# 添加了一个具有2048个神经元的全连接层，并使用ReLU激活函数进行非线性变换。
model.add(Dense(2048,activation='relu'))
# 添加了一个丢弃率为0.2的Dropout层，
# 用于在训练过程中随机丢弃一部分神经元，以减少过拟合的风险。
model.add(Dropout(0.2))
# 再添加了一个具有512个神经元的全连接层，同样使用ReLU激活函数。
model.add(Dense(512,activation='relu'))
# 再添加了一个具有128个神经元的全连接层，同样使用ReLU激活函数。
model.add(Dense(128,activation='relu'))
# 最后添加了一个具有10个神经元的输出层，使用Softmax激活函数进行多分类预测。
model.add(Dense(10,activation='softmax'))
# 用model.summary()方法打印出模型的结构摘要信息，包括每一层的名称、类型、输出形状等。
model.summary()


#编译
# 从tensorflow.keras.losses模块导入了categorical_crossentropy损失函数，
# 用于多分类问题的评估和优化
from tensorflow.keras.losses import categorical_crossentropy
# 导入了两种优化器：SGD（随机梯度下降）和Adam（自适应矩估计）。
from tensorflow.keras.optimizers import SGD,Adam
# 使用model.compile()方法对模型进行编译。在该方法中，需要指定损失函数、
# 优化器以及评估指标。在这里，损失函数选择了categorical_crossentropy，
# 优化器选择了SGD()（默认学习率为0.01），评估指标选择了accuracy（准确率）
model.compile(loss=categorical_crossentropy,optimizer=SGD(),metrics=['accuracy'])


#训练
# 从tensorflow.keras模块导入了callbacks子模块。然后，创建了三个回调函数对象
from tensorflow.keras import callbacks
# 使用callbacks.TensorBoard()创建一个TensorBoard回调函数，
# 用于可视化训练过程中的损失和指标变化。log_dir参数指定了日志文件保存的目录。
callback1=callbacks.TensorBoard(log_dir='./view')
# 使用callbacks.ModelCheckpoint()创建一个模型检查点回调函数，
# 用于在每个训练周期结束时保存模型的权重。filepath参数指定了保存文件的路径，
# monitor参数指定了监控指标（在这里是验证集上的损失），
# save_best_only参数设置为True表示只保存最佳性能的模型权重
callback2=callbacks.ModelCheckpoint(filepath='./save',monitor='val_loss',save_best_only=True)
# 使用callbacks.EarlyStopping()创建一个早停回调函数，
# 用于在验证集上的性能不再提升时提前终止训练。monitor参
# 数指定了监控指标（在这里是验证集上的损失），
# patience参数设置了容忍多少个训练周期内没有性能提升
callback3=callbacks.EarlyStopping(monitor='val_loss',patience=4)
# 使用model.fit()方法对模型进行训练，使用了前面定义的三个回调函数对象作为回调函数列表的元素
model.fit(X_train,y_train,validation_split=0.2,epochs=25,callbacks=[callback1,callback2,callback3])

# 保存模型
model.save('./model_weather.h5')